﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Dashboard.ClusteringSvc;
using UI.Dendrogram;

namespace Dashboard
{
    public partial class ClusterDendrogram : UserControl
    {
        private DocumentClusteringOutput _ClusterOutput;

        public ClusterDendrogram()
        {
            InitializeComponent();
            this.SizeChanged += new SizeChangedEventHandler(ClusterDendrogram_SizeChanged);
        }

        void ClusterDendrogram_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            //this.dendrogram.Width = this.ActualWidth;
            //this.dendrogram.Height = this.ActualHeight;
        }


        #region dendrogram data
        //private BinaryHierarchicalData GetClusterTree(DocumentClusteringOutput output)
        //{
        //    Dictionary<double, List<string>> distanceDocPairs = this.IndexDocPairsByDistance(output.DocDocDistances);
        //    List<double> distances=new List<double>();
        //    distances.AddRange(distanceDocPairs.Keys);
        //    distances.Sort();
        //    BinaryHierarchicalData root = null;
        //    List<int> processedDocIDs=new List<int>();
        //    Dictionary<int,int> docHierarchies=new Dictionary<int, int>();
        //    Dictionary<int,BinaryHierarchicalData> hierarchies=new Dictionary<int, BinaryHierarchicalData>();
        //    foreach(double distance in distances)
        //    {
        //        List<string> docPairs = distanceDocPairs[distance];
        //        foreach(string docPair in docPairs)
        //        {
        //            string[] docIDStrs = docPair.Split(new char[] {':'});
        //            int docID1 = int.Parse(docIDStrs[0]);
        //            int docID2 = int.Parse(docIDStrs[1]);
        //            if(!processedDocIDs.Contains(docID1))
        //            {
        //                if(docHierarchies.ContainsKey(docID2))
        //                {
        //                    int hierarchyID = docHierarchies[docID2];
        //                    BinaryHierarchicalData childHierarchy = hierarchies[hierarchyID];
        //                    int newHierarchyID = this.GetNextHierarchyID(hierarchies);
        //                    BinaryHierarchicalData newHierarchy =
        //                        new BinaryHierarchicalData()
        //                            {
        //                                Distance = distance,
        //                                ID = newHierarchyID,
        //                                Label = "Cluster " + newHierarchyID,
        //                                LeftChild = childHierarchy,
        //                                RightChild = null,
        //                                Parent = null,
        //                                Tag = docID1
        //                            };

        //                }
        //            }
        //        }
        //    }
        //}

        //private BinaryHierarchicalData GetTermTree(DocumentClusteringOutput output)
        //{

        //}

        //private int GetNextHierarchyID(Dictionary<int,BinaryHierarchicalData> hierarchies)
        //{
        //    int lastID = 0;
        //    foreach(int id in hierarchies.Keys)
        //    {
        //        if(id>lastID)
        //            lastID = id;
        //    }
        //    return lastID + 1;
        //}

        //private int GetRootHierarchyIDForDoc(int docID, List<BinaryHierarchicalData> hierarchies)
        //{
            
        //}

        private Dictionary<double, List<string>> IndexDocPairsByDistance(Dictionary<int, Dictionary<int, double>> docDocDistances)
        {
            Dictionary<double, List<string>> distanceDocPairs = new Dictionary<double, List<string>>();
            List<int> docIDs = new List<int>();
            docIDs.AddRange(docDocDistances.Keys);
            for (int i = 0; i < docIDs.Count; i++)
            {
                int fromDocID = docIDs[i];
                for (int k = i + 1; k < docIDs.Count; k++)
                {
                    int toDocID = docIDs[k];
                    string docPair = string.Format("{0}:{1}", fromDocID, toDocID);
                    if (toDocID < fromDocID)
                        docPair = string.Format("{0}:{1}", toDocID, fromDocID);
                    double distance = docDocDistances[fromDocID][toDocID];
                    if (distanceDocPairs.ContainsKey(distance))
                    {
                        List<string> docPairs = distanceDocPairs[distance];
                        docPairs.Add(docPair);
                        distanceDocPairs[distance] = docPairs;
                    }
                    else
                    {
                        List<string> docPairs = new List<string>();
                        docPairs.Add(docPair);
                        distanceDocPairs.Add(distance, docPairs);
                    }
                }
            }
            return distanceDocPairs;
        }

        private Dictionary<double, List<string>> IndexTermPairsByDistance(Dictionary<int, Dictionary<int, double>> termTermDistances)
        {
            Dictionary<double, List<string>> distanceTermPairs = new Dictionary<double, List<string>>();
            List<int> termIDs = new List<int>();
            termIDs.AddRange(termTermDistances.Keys);
            for (int i = 0; i < termIDs.Count; i++)
            {
                int fromTermID = termIDs[i];
                for (int k = i + 1; k < termIDs.Count; k++)
                {
                    int toTermID = termIDs[k];
                    string termPair = string.Format("{0}:{1}", fromTermID, toTermID);
                    if (toTermID < fromTermID)
                        termPair = string.Format("{0}:{1}", toTermID, fromTermID);
                    double distance = termTermDistances[fromTermID][toTermID];
                    if (distanceTermPairs.ContainsKey(distance))
                    {
                        List<string> docPairs = distanceTermPairs[distance];
                        docPairs.Add(termPair);
                        distanceTermPairs[distance] = docPairs;
                    }
                    else
                    {
                        List<string> docPairs = new List<string>();
                        docPairs.Add(termPair);
                        distanceTermPairs.Add(distance, docPairs);
                    }
                }
            }
            return distanceTermPairs;
        }
        #endregion

        private void ckShowDocTree_Click(object sender, RoutedEventArgs e)
        {
            this.DisplayClusteringOutput(this._ClusterOutput);
        }

        private void ckShowTermTree_Click(object sender, RoutedEventArgs e)
        {
            this.DisplayClusteringOutput(this._ClusterOutput);
        }

        private void ckShowHeatmap_Click(object sender, RoutedEventArgs e)
        {
            this.DisplayClusteringOutput(this._ClusterOutput);
        }

        #region bind data
        public void LoadClusterData(DocumentClusteringOutput output)
        {
            this._ClusterOutput = output;
            this.DisplayClusteringOutput(this._ClusterOutput);
        }

        private void DisplayClusteringOutput(DocumentClusteringOutput output)
        {
            BinaryHierarchicalData docTree = BinaryHierarchicalDataUtil.BuildBinaryHierarchy(output.DocDocDistances);
            List<LeafData> docLeaves = BinaryHierarchicalDataUtil.GetLeavesForBranch(docTree);
            for (int i = 0; i < docLeaves.Count; i++)
            {
                if (output.DocTitles.ContainsKey(docLeaves[i].ID))
                    docLeaves[i].Label = output.DocTitles[docLeaves[i].ID];
            }
            BinaryHierarchicalData termTree = BinaryHierarchicalDataUtil.BuildBinaryHierarchy(output.TermTermDistances);
            List<LeafData> termLeaves = BinaryHierarchicalDataUtil.GetLeavesForBranch(termTree);
            for (int i = 0; i < termLeaves.Count; i++)
            {
                if (output.AllTerms.ContainsKey(termLeaves[i].ID))
                    termLeaves[i].Label = output.AllTerms[termLeaves[i].ID];
            }

            Dictionary<LeafData, Dictionary<LeafData, int>> rowColCells = new Dictionary<LeafData, Dictionary<LeafData, int>>();
            Dictionary<int, string> cellLabels = new Dictionary<int, string>();
            Dictionary<int, string> cellTooltips = new Dictionary<int, string>();
            Dictionary<int, double> cellValues = new Dictionary<int, double>();
            int cellID = 0;
            foreach (LeafData docLeaf in docLeaves)
            {
                BinaryHierarchicalData docCluster = docLeaf.Parent;
                bool isLeft = (docCluster.LeftLeaf != null && docCluster.LeftLeaf.ID == docLeaf.ID);
                Dictionary<LeafData, int> rowCells1 = new Dictionary<LeafData, int>();
                foreach (LeafData termLeaf in termLeaves)
                {
                    BinaryHierarchicalData termCluster = termLeaf.Parent;
                    bool isTermLeft = (termCluster.LeftLeaf != null && termCluster.LeftLeaf.ID == termLeaf.ID);
                    cellID++;
                    rowCells1.Add(termLeaf, cellID);
                    cellLabels.Add(cellID, termLeaf.Label);
                    double weight = 0;
                    if (output.TermWeights.ContainsKey(termLeaf.ID))
                        weight = output.TermWeights[termLeaf.ID];
                    cellTooltips.Add(cellID, "tool tip ... " + cellID);
                    cellValues.Add(cellID, weight);
                }
                rowColCells.Add(docLeaf, rowCells1);
            }

            this.dendrogram.BindData(
                this.ckShowTermTree.IsChecked.Value,
                this.ckShowHeatmap.IsChecked.Value,
                docTree, termTree, rowColCells, cellLabels, cellTooltips, cellValues);
        }
        #endregion
    }
}
